CMP-BCx

← Zurück zum Forum

Wie gewünscht ein eigener Beitrag zum Thema Vergleichen von Werten mit dem passenden Branch Befehl. Ich habe mir hierzu mal eine Tabelle angelegt, die mir immer sehr hildreich ist, um nicht bei jedem Vergleich wieder von vorne nachdenken zu müssen:

Ist A kleiner als B?

LDA     A
CMP     B
BCC -> Ja A<B

Ist A kleiner oder gleich als B?

LDA B
CMP A
BCS -> Ja A<=B

Ist A größer als B?

LDA B
CMP A
BCC -> Ja A>B

Ist A größer gleich als B?

LDA A
CMP B
BCS -> Ja A>=B

... nur der Vollständigeit wegen:

Ist A gleich B?

LDA A
CMP B
BEQ -> Ja A=B

Ist A ungleich B?

LDA A
CMP B
BNE -> Ja A<>B

Noch eine kleine Erklärung:

Der CMP Befehl macht eigentlich nichts anderes als den Vergleichswert vom Akku zu subtrahieren ohne aber das Ergebnis zu speichern. Sehr wohl werden aber die enstprechenden Flags für das Ergebnis gesetzt, entsprechend dem SBC-Befehl. Also das N,Z,C oder/und V Flag (Ein SEC Befehl vor dem CMP ist übrigens nicht notwendig)

Jetzt kann man sich leicht die entsprechenden Branch-Befehle herleiten: Sind z.B. beide Werte gleich, so ergibt die interne Subtraktion ja Null. Das Ergebnis wird zwar verworfen , aber das Zero-Bit wird gesetzt und kann somit mit BEQ und BNE (also Null oder Nicht-Null) abgefragt werden. Ist der Wert im Akku kleiner dem Vergleichswert, so ist das Ergebnis der simulierten Subtraktion negativ und somit ist das N-Flag gesetzt. Also wäre hier der Branch Befehl BMI (Sprung wenn Minus) Alle anderen Vergleichsabfragen kann man sich jetzt leicht herleiten ...

BRanch.jpg

Anhänge:

Schleife von 5 bis 1

        LDX #5
Loop:       NOP
        NOP
        DEX
        BNE Loop

Schleife von 5 bis 0

        LDX #5
Loop:       NOP
        NOP
        DEX
        BPL Loop

Für NOP natürlich den eigenen Code einsetzen 😉

BNE verzweigt wenn das letzte Ergebnis nicht 0 war. BPL verweigt wenn das letzte Ergebnis positiv war.

Meine Projekte findest Du hier...

Und entsprechend noch in die andere Richtung von 1 bis 5:

          LDX #1
LOOP:     NOP
          NOP
          INX
          CPX #6
          BNE LOOP

BNE verzweigt solange X nicht den Wert 6 hat. Da die Inkrementierung am Ende der Schleife erfolgt ist der Vergleichswert um 1 höher dem gewünschten Ziel.

... und noch eine Schleife von 0 bis 255:

          LDX #0
LOOP:     NOP
          NOP
          INX
          BNE LOOP

Die Schleife wird beendet sobald der Wert nach der Inkrementierung wieder 0 ist

Eine kleine Ergänzung habe ich hier auch noch:

MADS bietet ja die Funktion #If .and .or #End an. Ich persönlich mag diese Funktion, da sie sehr einfach zu lesen ist und übersichtlich und schnell programmiert ist. Leider ist der Code nicht wirklich optimiert - eine gleiche Funktion erreicht man durch CMP / BCC / BCS mit fast der Hälfte des Codes und entsprechend Geschwindigkeitsgewinn... zur Übersicht habe ich mal den Code für eine If And - Anweisung:

In MADS:

        #if .byte var1<#10
        .... hier steht der Code ....
        #end

wird zu:

        lda var1
        cmp #10
        bcs weiter
        .... hier steht der Code ....
weiter      

und dann in MADS:

        #if .byte var1>=#120 .and var4<#240
        .... hier steht der Code ....
        #end

wird zu:

        lda var1
        cmp #120
        bcc weiter
        cmp #240
        bcs weiter
        .... hier steht der Code ....

weiter              

Zur besseren Übersicht habe ich hier extra eine Variable (var1) mit Werten verglichen, man kann natürlich auch statt der Werte weitere Variablen einsetzen.

Vielen Dank Olix für die Tipps.

BTW: http://6502.org/tutorials/compare_beyond.html ist ein sehr schöner Artikel dazu, wer ein wenig tiefer in die Materie einsteigen möchte. Gerade mit vorzeichenbehafteten Zahlen sei es 8 oder 16 bit wird es echt komisch.

Wer nur auf var1 auf 0 prüfen möchte:

 lda var1
 beq sprung_wenn_var1_ist_0

in 16 bit

 lda var1
 ora var1+1     ; hier werden beide Teile der Zahl zusammen geodert.
 beq sprung_wenn_var1_ist_0

Lars